package com.yc.sole.system.repository;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yc.sole.common.enums.TrueOrFalse;
import com.yc.sole.framework.exception.BaseException;
import com.yc.sole.framework.mybatis.page.Paging;
import com.yc.sole.framework.mybatis.util.PageUtil;
import com.yc.sole.system.dto.SequenceRuleDto;
import com.yc.sole.system.entity.Sequence;
import com.yc.sole.system.entity.SequenceRule;
import com.yc.sole.system.enums.SequencePrefixRule;
import com.yc.sole.system.exception.SysResultEnum;
import com.yc.sole.system.mapper.SequenceRuleMapper;
import com.yc.sole.system.request.SequenceRuleQueryReq;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;

/**
 * @author yizuomin
 * @date 2024/3/6 17:08
 **/
@Service
@RequiredArgsConstructor
public class SequenceRuleRepository extends ServiceImpl<SequenceRuleMapper, SequenceRule> {

    private final SequenceRepository sequenceRepository;

    /**
     * 新增
     *
     * @param sequenceRuleDto
     * @return RestResult
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveSequenceRule(SequenceRuleDto sequenceRuleDto) {
        SequenceRule entity = new SequenceRule();
        BeanUtil.copyProperties(sequenceRuleDto, entity);
        this.save(entity);
    }

    /**
     * 通过Id修改
     *
     * @param sequenceRuleDto
     * @return RestResult
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateSequenceRuleById(SequenceRuleDto sequenceRuleDto) {
        SequenceRule entity = new SequenceRule();
        BeanUtil.copyProperties(sequenceRuleDto, entity);
        this.updateById(entity);
    }

    /**
     * 通过id批量删除
     *
     * @param ids
     * @return RestResult
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteSequenceRuleByIds(Collection<Long> ids) {
        this.removeBatchByIds(ids);
    }

    /**
     * 根据id获取
     *
     * @param ids
     * @return RestResult
     */
    public List<SequenceRuleDto> selectSequenceRuleByIds(Set<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return BeanUtil.copyToList(this.listByIds(ids), SequenceRuleDto.class);
    }

    /**
     * 根据id获取
     *
     * @param id
     * @return RestResult
     */
    public SequenceRuleDto selectSequenceRuleById(Long id) {
        return BeanUtil.copyProperties(this.getById(id), SequenceRuleDto.class);
    }

    /**
     * 分页查询
     *
     * @param page
     * @return RestResult
     */
    public Paging<SequenceRuleDto> selectSequenceRulePage(Paging page, SequenceRuleQueryReq ruleQueryReq) {
        LambdaQueryWrapper<SequenceRule> queryWrapper = Wrappers.<SequenceRule>lambdaQuery()
                .like(CharSequenceUtil.isNotBlank(ruleQueryReq.getSequenceCode()), SequenceRule::getSequenceCode, ruleQueryReq.getSequenceCode())
                .like(CharSequenceUtil.isNotBlank(ruleQueryReq.getSequenceName()), SequenceRule::getSequenceName, ruleQueryReq.getSequenceName())
                .orderByDesc(SequenceRule::getId);
        return PageUtil.pageCopy(this.page(PageUtil.toMybatisPage(page), queryWrapper), SequenceRuleDto.class);
    }

    /**
     * 获取序列号
     *
     * @param sequenceCode
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public String getSequenceNo(String sequenceCode) {
        SequenceRule sequenceRule = this.getOne(Wrappers.<SequenceRule>lambdaQuery().eq(SequenceRule::getSequenceCode, sequenceCode));
        if (Objects.isNull(sequenceRule)) {
            throw new BaseException(SysResultEnum.SEQUENCE_RULE_NOT_FOUND, sequenceCode);
        }
        String prefixStr;
        if (SequencePrefixRule.NONE.equals(sequenceRule.getPrefixRule())) {
            prefixStr = "NONE";
        } else if (SequencePrefixRule.FIXED.equals(sequenceRule.getPrefixRule())) {
            prefixStr = sequenceRule.getPrefix();
        } else {
            prefixStr = DateUtil.format(LocalDateTime.now(), sequenceRule.getPrefixRule().getDescription());
        }
        // 查询序列
        LambdaQueryWrapper<Sequence> queryWrapper = Wrappers.<Sequence>lambdaQuery()
                .eq(Sequence::getSequenceCode, sequenceCode)
                .eq(Sequence::getPrefix, prefixStr);
        Sequence sequence = sequenceRepository.getOne(queryWrapper);
        if (Objects.isNull(sequence)) {
            sequence = new Sequence();
            sequence.setSequenceCode(sequenceCode);
            sequence.setPrefix(prefixStr);
            sequence.setCurrentValue(1L);
            sequenceRepository.save(sequence);
        }

        Long currentValue = sequence.getCurrentValue();
        LambdaUpdateWrapper<Sequence> updateWrapper = Wrappers.<Sequence>lambdaUpdate()
                .eq(Sequence::getId, sequence.getId())
                .eq(Sequence::getCurrentValue, currentValue)
                .set(Sequence::getCurrentValue, currentValue + 1);
        boolean update = sequenceRepository.update(updateWrapper);
        if (!update) {
            throw new BaseException(SysResultEnum.GET_SEQ_NO_FAIL);
        }
        if (TrueOrFalse.TRUE.equals(sequenceRule.getAutoFill())) {
            if (SequencePrefixRule.NONE.equals(sequenceRule.getPrefixRule()) && currentValue.toString().length() < sequenceRule.getLength()) {
                return "1" + CharSequenceUtil.padPre(currentValue.toString(), sequenceRule.getLength() - 1, "0");
            } else {
                return prefixStr + CharSequenceUtil.padPre(currentValue.toString(), sequenceRule.getLength() - prefixStr.length(), "0");
            }
        }
        if (SequencePrefixRule.NONE.equals(sequenceRule.getPrefixRule())) {
            return String.valueOf(currentValue);
        }
        return prefixStr + currentValue;
    }
}
